package arena.weapon;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;

import gameframework.game.SpriteManagerDefaultImpl;
import arena.soldier.SoldierGame;
import arena.utils.CareTaker;

/**
 * @param <W>
 *            Express the link with a specific type of weapon (e.g.,
 *            SoldierWithShield is linked with a Shield, not any kind of
 *            weapon).
 */
public abstract class SoldierArmed<W extends Weapon> extends SoldierGame{
	protected SoldierGame soldier;
	protected W weapon;
	protected CareTaker gardian = new CareTaker();
	private static final float WEARINESS_COEF = 0; // XXX temporarily inhibited

	protected boolean movable = true;
	private final SpriteManagerDefaultImpl spriteManager;
	public static final int RENDERING_SIZE = 50;
	protected Point regenerePoint;
	protected boolean isFighting =false;
	protected boolean vulnerable = false;
	protected boolean isSaveInMemento = false;
	protected int vulnerableTimer = 0;

	SoldierArmed(SoldierGame s, W a) {
		soldier = s;
		weapon = a;		
		spriteManager = s.getSpriteManager();
	}
	
	public void setInvulnerable(int timer) {
		soldier.setInvulnerable(timer);
	}

	public boolean isVulnerable() {
		return soldier.isVulnerable();
	}
	
	public void setFighting(boolean isFighting) {
		soldier.setFighting(true);
	}
	
	public boolean isFighting() {
		return soldier.isFighting();
	}
	
	@Override
	public SpriteManagerDefaultImpl getSpriteManager() {
		return spriteManager;
	}

	public String getName() {
		return soldier.getName();
	}

	public float getHealthPoints() {
		return soldier.getHealthPoints();
	}

	public boolean alive() {
		return soldier.alive();
	}

	public void heal() {
		soldier.heal();
	}

	public void fixWeapon() {
		weapon.fix();
	}

	public boolean parry(float force) {
		float effectiveForce = force - weapon.getParryValue();
		if (effectiveForce <= 1) effectiveForce = 1;
		//Effective force is at least 1 (weariness effect)
		weapon.damageCompute(WEARINESS_COEF);
		return soldier.parry(effectiveForce);
	}

	public float strike() {
		float force = soldier.strike() + weapon.getStrikeValue();
		weapon.damageCompute(WEARINESS_COEF);
		return force;
	}

	@Override
	public Rectangle getBoundingBox() {
		return (new Rectangle(0, 0, RENDERING_SIZE, RENDERING_SIZE));
	}

	@Override
	public void oneStepMoveAddedBehavior() {
		soldier.oneStepMoveAddedBehavior();
	}
	public void oneStepMove(){
		soldier.oneStepMove();
	}
	
	public void drawBarLife (Graphics g){
		int lifeBarWidth = getBoundingBox().width/2;
		float life = (getHealthPoints()/soldier.getHealthPointAtBeginning());
		g.setColor(Color.BLACK);
		g.drawRect(this.getPosition().x+(getBoundingBox().width)/4, this.getPosition().y, lifeBarWidth, 7);
		
		if (life > 0.33){
			g.setColor(Color.GREEN);
		}
		else
			g.setColor(Color.RED);

		//Drawing life bar inside
		g.fillRect((this.getPosition().x+(getBoundingBox().width)/4)+1,this.getPosition().y+1, (int) ((lifeBarWidth-1)*life), 6);
	}
	public void drawMagicBar (Graphics g){
		int magicBarWidth = getBoundingBox().width/2;
		float magic = (soldier.getMagic()/soldier.getMagicAtBeginning());
		g.setColor(Color.BLACK);
		g.drawRect(this.getPosition().x+(getBoundingBox().width)/4, this.getPosition().y-10, magicBarWidth, 7);		
		g.setColor(Color.cyan);
		
		//Drawing life bar inside
		g.fillRect((this.getPosition().x+(getBoundingBox().width)/4)+1,this.getPosition().y+1-10, (int) ((magicBarWidth-1)*magic), 6);
	}
	
	@Override
	public void draw(Graphics g) {
		soldier.draw(g);
	}

	public Object saveToMemento() { 
        System.out.println("Sauvegarde dans le memento.");        
        return new Memento(this.soldier); 
    }
	
    public void restoreFromMemento(Object m) {
        if (m instanceof Memento) {
            Memento memento = (Memento)m; 
            this.soldier = (SoldierGame) memento.getSavedState().clone(); 
        }
    }
    
    //Memento
    private static class Memento {
    	protected SoldierGame soldier; 
        public Memento(SoldierGame soldier2) 
        { 
        	this.soldier = (SoldierGame)soldier2.clone();
        }
        
        public SoldierGame getSavedState() 
        { 
        	return this.soldier; 
        }
    }
	    
    public void saveCheckPoint(Point point){    	
    	this.gardian.addMemento(saveToMemento());
    	this.regenerePoint = point;
    	this.isSaveInMemento = true;
    }
    
	public Point getRegenerePoint(){
		return this.regenerePoint;
	}
	
   public void restoreCheckPoint(){
	restoreFromMemento( gardian.getLastMemento() );
   }

   public float getHealthPoint(){
	  return  soldier.getHealthPoints();
   }
   
   public void setHealthPoint(float life){
	   this.soldier.setHealthPoints(life);
   }
   
   public boolean isSaveInMemento(){
	   return this.isSaveInMemento;
   }
   
   	public boolean receiveAttack(float force) {
	   if (force > soldier.getHealthPoints()){
		   this.soldier.setHealthPoints(0);
		   return true;
		}
		else{
			this.soldier.setHealthPoints(soldier.getHealthPoints()-force);
			return false;
		}
   	}
   	public Point getPosition(){
	   return soldier.getPosition();
	}
   
   	public void createTower(){
		soldier.createTower();
	}
	
	public void setPosition (Point p){
		soldier.setPosition(p);
	}
}
